/*
 * Amkai Enterprise Solution (AES.) 
 * Copyright 2004-2008 by Amkai(TM), Inc.
 * www.amkai.com
 * 
 * Project: webservice
 * Package: com.amkai.aes.webservice.binary.objecthandler.diee
 * File: DIEEHandler.java
 * Created: Feb 12, 2008 3:18:03 PM
 * Author: kokog 
 * 
 */
package com.amkai.aes.webservice.binary.objecthandler.diee;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.w3c.dom.Document;

import com.amkai.aes.aescommon.diee.GeneratedFiles;
import com.amkai.aes.aescommon.files.FileRemover;
import com.amkai.aes.aescommon.service.diee.DIEECommonUtils;
import com.amkai.aes.aescommon.service.diee.DIEEJob;
import com.amkai.aes.aescommon.service.diee.DIEEResult;
import com.amkai.aes.generatedbeans.audittrail.AuditTrail;
import com.amkai.aes.generatedbeans.binarymgr.BinaryData;
import com.amkai.aes.generatedbeans.diee.FormPrintingKind;
import com.amkai.aes.generatedbeans.diee.ReportDefinition;
import com.amkai.aes.generatedbeans.diee.ReportGroup;
import com.amkai.aes.generatedbeans.diee.ReportKind;
import com.amkai.aes.generatedbeans.diee.ReportTask;
import com.amkai.aes.generatedbeans.diee.ServerTask;
import com.amkai.aes.generatedbeans.diee.TaskXML;
import com.amkai.aes.generatedbeans.organization.Department;
import com.amkai.aes.generatedbeans.passport.Passport;
import com.amkai.aes.server.diee.DIEEClientTaskEnvironment;
import com.amkai.aes.server.diee.DIEEClientTaskHandler;
import com.amkai.aes.server.diee.DIEEServerUtils;
import com.amkai.common.base.diee.IReportGroupItem;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.diee.ClientTask;
import com.amkai.diee.ReportRuntimeInformation;
import com.amkai.diee.Rule;
import com.amkai.diee.utils.DIEEDebugger;
import com.amkai.diee.utils.Utils;
import com.amkai.diee.utils.reportmill.RMSerializer;
import com.amkai.diee.utils.taskmanager.TaskUtils;
import com.amkai.extensions.server.services.ServerServiceManager;
import com.sun.org.apache.xml.internal.serialize.Method;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

public class DIEEHandler extends AbstractDIEEHandler<DIEEJob, DIEEResult>  {
	
	private final HashMap<String, ReportRuntimeInformation> runtimeInfos = new HashMap<String, ReportRuntimeInformation>();
	
	@Override
	protected DIEEResult createResult() {
		return new DIEEResult();
	}
	
	@Override
	protected String getName() {
		return "DIEE JOB";
	}
	
	private final class ClientTaskEnvironment implements DIEEClientTaskEnvironment {
		
		private final SessionManager sessionManager;
		private final DIEEDebugger debugger;
		private final DIEEJob job;
		private Thread memoryThread;
		private Long[] memoryLog;

		
		public ClientTaskEnvironment(SessionManager sessionManager,
				DIEEDebugger debugger, DIEEJob job,
				Thread memoryThread, Long[] memoryLog) {
			super();
			this.sessionManager = sessionManager;
			this.debugger = debugger;
			this.job = job;
			this.memoryThread = memoryThread;
			this.memoryLog = memoryLog;
		}

		@Override
		public DIEEDebugger getDebugger() {
			return debugger;
		}

		@Override
		public Logger getLogger() {
			return DIEEHandler.this.getLogger();
		}

		@Override
		public Map<String, ReportRuntimeInformation> getRuntimeInfos() {
			return runtimeInfos;
		}
		
		@Override
		public SessionManager getSessionManager() {
			return sessionManager;
		}

		@Override
		public void logMemoryUsage() {
			if (memoryThread==null)
				DIEEHandler.this.logMemory(memoryLog);
		}

		@Override
		public void stopMemoryUsageLogging() {
			if (memoryThread!=null) {
				memoryThread.stop();
				memoryThread = null;
			}
		}
		
		@Override
		public boolean isDevelopmentMode() {
			return job.isDevelopmentMode();
		}
		
		@Override
		public boolean isRequireQueryData() {
			return job.query.isRequireQueryData();
		}
		
		@Override
		public boolean isRequireSchemaXml() {
			return job.query.reportMill.isRequireSchemaXml();
		}

		@Override
		public void recordHistory(Department department, Passport passport,
				String uniqueId, ReportDefinition def, DIEEResult result,
				List<Rule> rules) throws Exception {
			DIEEHandler.this.recordHistory(job.getModuleAuditTrail(), sessionManager, department, passport, uniqueId, def, result, memoryLog, rules);
		}
		
	}
	
	@Override
	protected void checkMemoryUsage(DIEEJob job, Serializable object) throws Exception {
		// AES-17128: do not check memory usage if we just want to stop a report
		if (object!=null || job.getUniqueIdToStop()==null)
			super.checkMemoryUsage(job, object);
	}
	
	@Override
	public void process(DIEEJob job, Serializable object, DIEEResult result, SessionManager sessionManager, DIEEDebugger debugger) throws Exception, Error {
		
		boolean LOG_MEMORY = false;
		Thread memoryThread = null;
		Long[] memoryLog = null;
		
		if (LOG_MEMORY) {
			memoryThread = getMemoryCheckThread();
			memoryThread.start();
		} else {
			if (job.isDevelopmentMode()) {
				clearMemoryLog();
			} else {
				memoryLog = new Long[4];
			}
			logMemory(memoryLog);
		}
		
		// Department
		Department department = job.getModuleDepartment();
		if (department!=null) department = sessionManager.get(Department.class, department.getId());
		info("Department: "+department);
		String timeZone = (department==null ? null : department.getTimeZone());
		info("Time Zone: " + timeZone);

		ClientTaskEnvironment environment = new ClientTaskEnvironment(sessionManager, debugger, job, memoryThread, memoryLog);

		if (object!=null && object instanceof ClientTask) {
			ClientTask clientTask = (ClientTask)object;
			clientTask.setDepartment(department);
			DIEEClientTaskHandler handler = new DIEEClientTaskHandler(environment);
			handler.process(clientTask, result);
		}
		
		environment.stopMemoryUsageLogging();
		
		if (job.getUniqueIdToStop()!=null) stopReport(job.getUniqueIdToStop());
		
		if (job.report.isUsed()) {
			info("Processing a report group related job.");
			int operationType = job.report.getOperationType();
			// DELETING one or more report group:
			if (operationType==DIEEJob.ReportClass.OPERATION_DELETE_GROUP) {
				String s = "";
				for (Long id : job.report.getIds()) {
					if (id!=null) {
						if (s.length()>0) s += ", ";
						s += id.toString();
					}
				}
				if (s.length()>0) {
					info("Deleting the report groups with id: "+s+"...");
					sessionManager.openTransaction();
					List<ReportGroup> list = (List<ReportGroup>)sessionManager.execute("from ReportGroup x where x.id in ("+s+")").list();
					for (ReportGroup group : list) {
						deleteReportGroup(group, sessionManager);
					}
					sessionManager.commitTransaction();
				}
			}
			// CREATING a new report group:
			else if (operationType==DIEEJob.ReportClass.OPERATION_CREATE_GROUP) {
				ReportGroup rg = new ReportGroup();
				rg.setKind(job.report.getReportGroupKind());
				rg.setActive(job.report.isVisible());
				rg.setSystemGroup(false);
				rg.setName(job.report.getName());
				rg.setDescription(job.report.getDescription());
				rg.setFormPrintingKind(job.report.getFormPrintingKind());
				Long parentId = job.report.getParentId();
				sessionManager.openTransaction();
				if (parentId!=null) {
					ReportGroup parent = getReportGroup(parentId, sessionManager);
					info("Persisting a report group in the parent "+parent.getName()+" #"+parent.getId()+"...");
					parent.addReportGroup(rg);
					sessionManager.update(parent);
				} else {
					info("Persisting a root report group...");
				}
				sessionManager.save(rg);
				sessionManager.commitTransaction();
				result.setReportGroupId(rg.getId());
				info("Persisting ok.");
			}
			// MOVING a report group:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MOVE_GROUP) {
				Long id = job.report.getId();
				info("Moving the report group #"+id+"...");
				sessionManager.openTransaction();
				ReportGroup group = getReportGroup(id, sessionManager);
				ReportGroup oldParent = group.getParent();
				if (oldParent!=null) {
					oldParent.removeReportGroup(group);
					sessionManager.update(oldParent);
				}
				Long parentId = job.report.getParentId();
				if (parentId!=null) {
					info("New parent is #"+parentId+".");
					ReportGroup newParent = getReportGroup(parentId, sessionManager);
					newParent.addReportGroup(group);
					group.setFormPrintingKind(newParent.getFormPrintingKind());
					sessionManager.update(newParent);
				} else {
					group.setParent(null);
					group.setFormPrintingKind(job.report.getFormPrintingKind());
					info("New parent is null.");
				}
				setFormPrintingKind(group, sessionManager);
				sessionManager.commitTransaction();
				result.setReportGroupId(id);
			}
			// MODIFYING a report group:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MODIFY_GROUP) {
				Long id = job.report.getId();
				if (id!=null) {
					info("Modifying the report group #"+id+"...");
					sessionManager.openTransaction();
					ReportGroup group = getReportGroup(id, sessionManager);
					info("New name: "+job.report.getName());
					group.setName(job.report.getName());
					info("New description: "+job.report.getDescription());
					group.setDescription(job.report.getDescription());
					group.setActive(job.report.isVisible());
					sessionManager.update(group);
					sessionManager.commitTransaction();
					result.setReportGroupId(id);
				} else {
					throw new Exception("No report group added.");
				}
			}
			// DELETING one or more report definition:
			else if (operationType==DIEEJob.ReportClass.OPERATION_DELETE_DEFINITION) {
				deleteItems(operationType, job.report.getIds(), result, sessionManager);
			}
			// CREATING a new report definition:
			else if (operationType==DIEEJob.ReportClass.OPERATION_CREATE_DEFINITION) {
				Long parentId = job.report.getParentId();
				if (parentId!=null) {
					sessionManager.openTransaction();
					ReportGroup group = getReportGroup(parentId, sessionManager);
					ReportDefinition def = new ReportDefinition();
					def.setReportKind(ReportKind.REPORT);
					def.setName(job.report.getName());
					def.setDescription(job.report.getDescription());
					def.setBeanClassName(job.report.getBeanClassName());
					group.addReportDefinition(def);
					info("Persisting the new report '"+def.getName()+"' in the parent #"+parentId+"...");
					sessionManager.save(def);
					sessionManager.update(group);
					result.setReportItem(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initReportDefinition(def));
					sessionManager.commitTransaction();
				} else {
					throw new Exception("No parent report group added.");
				}
			}
			// MOVING a report definition:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MOVE_DEFINITION) {
				Long id = job.report.getId();
				Long parentId = job.report.getParentId();
				if ((id!=null)&&(parentId!=null)) {
					info("Moving the report definition #"+id+" into the report group #"+parentId+"...");
					sessionManager.openTransaction();
					ReportDefinition def = getReportDefinition(id, sessionManager);
					ReportGroup oldGroup = def.getReportGroup();
					ReportGroup newGroup = getReportGroup(parentId, sessionManager);
					oldGroup.removeReportDefinition(def);
					newGroup.addReportDefinition(def);
					sessionManager.update(oldGroup);
					sessionManager.update(def);
					sessionManager.update(newGroup);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initReportDefinition(def));
					sessionManager.commitTransaction();
				} else if (id==null) {
					throw new Exception("No report definition added.");
				} else {
					throw new Exception("No report group added.");
				}
			}
			// MODIFYING a report definition:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MODIFY_DEFINITION) {
				Long id = job.report.getId();
				if (id!=null) {
					info("Modifying the report definition #"+id+"...");
					sessionManager.openTransaction();
					ReportDefinition def = getReportDefinition(id, sessionManager);
					info("New name: "+job.report.getName());
					def.setName(job.report.getName());
					info("New description: "+job.report.getDescription());
					def.setDescription(job.report.getDescription());
					sessionManager.update(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initReportDefinition(def));
					sessionManager.commitTransaction();
				} else {
					throw new Exception("No report definition added.");
				}
			}
			// SETTING the rpt data in an existing report definition
			else if (operationType==DIEEJob.ReportClass.OPERATION_MODIFY_DEFINITION_RPT) {
				Long id = job.report.getId();
				if (id!=null) {
					sessionManager.openTransaction();
					ReportDefinition def = getReportDefinition(id, sessionManager);
					BinaryData data = null;
					Long dataId = job.report.getBinaryDataId();
					if (dataId!=null) {
						info("Setting the binary data #"+dataId+" for report definition #"+id+"...");
						data = (BinaryData)sessionManager.execute("from BinaryData where id="+dataId).uniqueResult();
						if (data==null) error("The binary data does not exists!");
						def.setRptBinaryData(data);
					} else {
						info("No binary data added for report definition #"+id+"...");
					}
					String beanClassName = job.report.getBeanClassName();
					if (beanClassName!=null) {
						info("Setting the bean class name '"+beanClassName+"' for report definition #"+id+"...");
						def.setBeanClassName(beanClassName);
					}
					info("Persisting report definition #"+id+"...");
					sessionManager.update(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initReportDefinition(def));
					sessionManager.commitTransaction();
				} else {
					throw new Exception("No report definition added.");
				}
			}
			// DELETING one or more task xml:
			else if (operationType==DIEEJob.ReportClass.OPERATION_DELETE_TASK_XML) {
				deleteItems(operationType, job.report.getIds(), result, sessionManager);
			}
			// CREATING a new task xml:
			else if (operationType==DIEEJob.ReportClass.OPERATION_CREATE_TASK_XML) {
				Long parentId = job.report.getParentId();
				if (parentId!=null) {
					sessionManager.openTransaction();
					ReportGroup group = getReportGroup(parentId, sessionManager);
					TaskXML def = new TaskXML();
					def.setName(job.report.getName());
					def.setDescription(job.report.getDescription());
					def.setBeanClassName(job.report.getBeanClassName());
					def.setServerSide(job.report.isServerSide());
					group.addTaskXML(def);
					info("Persisting the new task xml '"+def.getName()+"' in the parent #"+parentId+"...");
					sessionManager.save(def);
					sessionManager.update(group);
					result.setReportItem(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initTaskXML(def));
					sessionManager.commitTransaction();
				} else {
					throw new Exception("No parent report group added.");
				}
			}
			// MOVING a task xml:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MOVE_TASK_XML) {
				Long id = job.report.getId();
				Long parentId = job.report.getParentId();
				if ((id!=null)&&(parentId!=null)) {
					info("Moving the task xml #"+id+" into the report group #"+parentId+"...");
					sessionManager.openTransaction();
					TaskXML def = getTaskXML(id, sessionManager);
					ReportGroup oldGroup = def.getReportGroup();
					ReportGroup newGroup = getReportGroup(parentId, sessionManager);
					oldGroup.removeTaskXML(def);
					newGroup.addTaskXML(def);
					sessionManager.update(oldGroup);
					sessionManager.update(def);
					sessionManager.update(newGroup);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initTaskXML(def));
					sessionManager.commitTransaction();
				} else if (id==null) {
					throw new Exception("No task xml added.");
				} else {
					throw new Exception("No report group added.");
				}
			}
			// MODIFYING a task xml:
			else if (operationType==DIEEJob.ReportClass.OPERATION_MODIFY_TASK_XML) {
				Long id = job.report.getId();
				if (id!=null) {
					info("Modifying the task xml #"+id+"...");
					sessionManager.openTransaction();
					TaskXML def = getTaskXML(id, sessionManager);
					info("New name: "+job.report.getName());
					def.setName(job.report.getName());
					info("New description: "+job.report.getDescription());
					def.setDescription(job.report.getDescription());
					info("Server side: "+job.report.isServerSide());
					def.setServerSide(job.report.isServerSide());
					sessionManager.update(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initTaskXML(def));
					sessionManager.commitTransaction();
					BinaryData data = def.getBinaryData();
					if (data!=null) {
						info("Updating binary data...");
						File f = ServerServiceManager.getInstance().getBinaryManager().downloadBinary(data);
						if (f!=null) {
							String xmlData = Utils.loadFileToString(f);
							FileRemover.getInstance().deleteFile(f);
							xmlData = TaskUtils.getCorrectedTaskData(def, xmlData);
							byte[] bytes = xmlData.getBytes();
							ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
							ServerServiceManager.getInstance().getBinaryManager().updateBinary(data, stream, bytes.length);
							stream.close();
						} else {
							error("File not exists in the binary store: "+data.getStoreName()+".");
						}
					}
				} else {
					throw new Exception("No task xml added.");
				}
			}
			// SETTING the xml data in an existing task xml
			else if (operationType==DIEEJob.ReportClass.OPERATION_MODIFY_TASK_XML_XML) {
				Long id = job.report.getId();
				if (id!=null) {
					sessionManager.openTransaction();
					TaskXML def = getTaskXML(id, sessionManager);
					BinaryData data = null;
					Long dataId = job.report.getBinaryDataId();
					if (dataId!=null) {
						info("Setting the binary data #"+dataId+" for task xml #"+id+"...");
						data = (BinaryData)sessionManager.execute("from BinaryData where id="+dataId).uniqueResult();
						if (data==null) {
							error("The binary data does not exists!");
						} else {
							File f = ServerServiceManager.getInstance().getBinaryManager().downloadBinary(data);
							TaskUtils.correctTask(def, new FileInputStream(f));
							FileRemover.getInstance().deleteFile(f);
						}
						def.setBinaryData(data);
					} else {
						info("No binary data added for task xml #"+id+"...");
					}
					info("Persisting task xml #"+id+"...");
					sessionManager.update(def);
					if (job.report.isRequireReportItem())
						result.setReportItem(DIEEServerUtils.initTaskXML(def));
					sessionManager.commitTransaction();
				} else {
					throw new Exception("No task xml added.");
				}
			}
			// QUERYING the report definitions
			else if (operationType==DIEEJob.ReportClass.OPERATION_QUERY_DEFINITIONS) {
				result.addReportItem(null);
				FormPrintingKind kind = job.report.getFormPrintingKind();
				if (kind!=null) {
					info("Querying the active report definitions with the form printing kind "+kind+"...");
					List<ReportGroup> groups = sessionManager.execute("from ReportGroup x where x.parent is null and x.active=true and x.formPrintingKindWrapper.id="+kind.ordinal()).list();
					for (ReportGroup group : groups) {
						addActiveReportDefinitionsToList(group, result);
					}
				} else if (job.report.getReportDefinitionSysIds()!=null) {
					for (String sysId : job.report.getReportDefinitionSysIds()) {
						info("Querying the report definition with the system id "+sysId+"...");
						List<ReportDefinition> defs = (List<ReportDefinition>)sessionManager.execute("from ReportDefinition where sysId='"+sysId+"'").list();
						for (ReportDefinition def : defs) {
							DIEEServerUtils.initReportDefinition(def);
							result.addReportItem(def);
						}
					}
				}
			}
		}
		if (job.report.isRequireGroupStructure()) {
			info("Querying the report group structure...");
			String s = null;
			if (job.report.getQueryMode()==DIEEJob.ReportClass.QUERY_MODE_GROUPS_FORM_PRINTING)
				s = "and x.formPrintingKindWrapper is not null";
			else if (job.report.getQueryMode()==DIEEJob.ReportClass.QUERY_MODE_GROUPS_NO_FORM_PRINTING)
				s = "and x.formPrintingKindWrapper is null";
			else if (job.report.getQueryMode()==DIEEJob.ReportClass.QUERY_MODE_GROUPS_ALL)
				s = "";
			if (s!=null) {
				List<ReportGroup> groups = sessionManager.execute("from ReportGroup x where x.parent is null and x.kindWrapper.id="+job.report.getReportGroupKind().ordinal()+" "+s+" order by x.name").list();
				for (ReportGroup g : groups) walkTroughReportGroup(g);
				result.setReportGroups(groups);
			}
		}
		List<Long> ids = job.report.getGroupIdsForItemList();
		if (ids!=null) {
			for (Long id : ids) {
				loadReportDefinitions(sessionManager, result, id, null, department);
			}
		}
		List<String> sysIds = job.report.getGroupSysIdsForItemList();
		if (sysIds!=null) {
			for (String sysId : sysIds) {
				loadReportDefinitions(sessionManager, result, null, sysId, department);
			}
		}
	}
	
	private final void logMemory(Long[] values) {
		if (values==null)
			logMemory();
		else {
			long current = System.currentTimeMillis() / 1000;
			if (values[0]==null || values[0]>current) values[0] = current;
			if (values[1]==null || values[1]<current) values[1] = current;
			Runtime r = Runtime.getRuntime();
			long used = r.totalMemory() - r.freeMemory();
			if (values[2]==null || values[2]>used) values[2] = used;
			if (values[3]==null || values[3]<used) values[3] = used;
		}
	}
	
	private final void stopReport(String uniqueId) {
		synchronized (this) {
			info("Stopping report # "+uniqueId+" ...");
			ReportRuntimeInformation info = runtimeInfos.remove(uniqueId);
			if (info!=null) {
				if (info.getReportName()!=null) {
					info("Report name: "+info.getReportName()+".");
				}
				info.setEnabled(false);
				info.deleteFiles();
			} else {
				info("Cannot find report.");
			}
		}
	}
	
	private final void recordHistory(
			AuditTrail moduleAuditTrail,
			SessionManager sm, Department department, Passport passport,
			String uniqueId, ReportDefinition def, DIEEResult result, Long[] values,
			List<Rule> rules) throws Exception {
		info("Report history by task unique id: "+uniqueId+"...");
		sm.openTransaction();
		try {
			if (values==null) values = getTimeAndMemoryLimits();
			int duration = 0;
			if (values[0]!=null && values[1]!=null)
				duration = new Long(values[1] - values[0]).intValue();
			int memory = 0;
			if (values[2]!=null && values[3]!=null)
				memory = new Long(values[3] - values[2]).intValue();
			DIEEServerUtils.recordHistory(moduleAuditTrail, sm, department, passport, uniqueId, def, Utils.toFormatKind(result.getResultKind()), duration, result.getResultSize(), memory, rules);
			sm.commitTransaction();
		} catch (Exception ex) {
			sm.rollbackTransaction();
			throw ex;
		}
	}
	
	private final String serializeRM(Map<String,?> data) throws IOException {
		RMSerializer serializer = new RMSerializer();
		File keyFile = File.createTempFile("diee-", ".ser");
		keyFile.deleteOnExit();
		File datFile = File.createTempFile("diee-", ".ser");
		datFile.deleteOnExit();
		try {
			FileOutputStream keyStr = new FileOutputStream(keyFile);
			FileOutputStream datStr = new FileOutputStream(datFile);
			serializer.serialize(data, keyStr, datStr);
			datStr.close();
			FileInputStream input = new FileInputStream(datFile);
			DIEECommonUtils.writeStreamToStream(input, keyStr, true);
		} catch (Exception ex) {
			FileRemover.getInstance().deleteFile(keyFile);
			FileRemover.getInstance().deleteFile(datFile);
			throw new IllegalStateException("Cannot serialize the data.", ex);
		}
		String ret = Utils.loadFileToString(keyFile);
		FileRemover.getInstance().deleteFile(keyFile);
		FileRemover.getInstance().deleteFile(datFile);
		return ret;
	}
	
	private final byte[] serializeXLS(HSSFWorkbook data) throws IOException {
		File datFile = File.createTempFile("diee-", ".ser");
		datFile.deleteOnExit();
		try {
			FileOutputStream datStr = new FileOutputStream(datFile);
			((HSSFWorkbook)data).write(datStr);
			datStr.close();
		} catch (Exception ex) {
			FileRemover.getInstance().deleteFile(datFile);
			throw new IllegalStateException("Cannot serialize the data.", ex);
		}
		byte[] ret = Utils.loadFileToBuffer(datFile);
		return ret;
	}
	
	private final String serializeXML(Document data) throws IOException {
		File datFile = File.createTempFile("diee-", ".ser");
		datFile.deleteOnExit();
		try {
			FileWriter writer = new FileWriter(datFile);
			XMLSerializer serializer = new XMLSerializer(writer, new OutputFormat(Method.XML, null, true));
			serializer.serialize((Document)data);
			writer.flush();
			writer.close();
		} catch (Exception ex) {
			FileRemover.getInstance().deleteFile(datFile);
			throw new IllegalStateException("Cannot serialize the data.", ex);
		}
		String ret = Utils.loadFileToString(datFile);
		FileRemover.getInstance().deleteFile(datFile);
		return ret;
	}
	
	private final void loadReportDefinitions(SessionManager sessionManager, DIEEResult result, Long groupId, String groupSysId, Department department) {
		String t;
		String where = "where ";
		String extraWhere = "";
		if (groupId!=null) {
			where += "x.reportGroup.id=" + groupId.toString();
			t = "#" + groupId;
		} else {
			where += "x.reportGroup.sysId='" + groupSysId +"'";
			t = "'" + groupSysId + "'";
		}
		if (department!=null) {
			extraWhere += " and (size(x.departmentKindAssociations)=0 or ka.departmentKindWrapper.id="+department.getDepartmentType().getKind().ordinal()+")";
			extraWhere += " and (size(x.departmentAssociations)=0 or da.department.id="+department.getId()+")";
		}
		List<ReportDefinition> defs = sessionManager.execute(
				"select x from ReportDefinition as x " +
				"left join x.departmentKindAssociations as ka " +
				"left join x.departmentAssociations as da " + where + extraWhere
			).list();
		boolean added = false;
		if (defs.size()>0) {
			for (ReportDefinition def : defs) DIEEServerUtils.initReportDefinition(def);
			if (groupId!=null)
				result.setReportItems(groupId, defs);
			else
				result.addReportItems(defs);
			added = true;
		}
		info("The count of the report definitions for group "+t+" is "+defs.size()+".");
		List<TaskXML> xmls = sessionManager.execute("select x from TaskXML as x " + where).list();
		if (xmls.size()>0) {
			for (TaskXML xml : xmls) DIEEServerUtils.initTaskXML(xml);
			if (groupId!=null)
				result.setReportItems(groupId, xmls);
			else
				result.addReportItems(xmls);
			added = true;
		}
		info("The count of the task XMLs for group "+t+" is "+defs.size()+".");
		List<ReportTask> tasks = sessionManager.execute(
				"select x from ReportTask as x " +
				"left join x.departmentKindAssociations as ka " +
				"left join x.departmentAssociations as da " + where + extraWhere
			).list();
		if (xmls.size()>0) {
			for (ReportTask task : tasks) DIEEServerUtils.initReportTask(task);
			if (groupId!=null)
				result.setReportItems(groupId, tasks);
			else
				result.addReportItems(tasks);
			added = true;
		}
		info("The count of the report tasks for group "+t+" is "+defs.size()+".");
		if (!added) {
			if (groupId!=null) result.setReportItems(groupId, new ArrayList<IReportGroupItem>());
		}
	}
	
	private final String getIdList(List<Long> ids) {
		String s = "";
		for (Long id : ids) {
			if (id!=null) {
				if (s.length()>0) s += ", ";
				s += id.toString();
			}
		}
		return s;
	}
	
	private final ReportGroup getReportGroup(Long id, SessionManager sessionManager) throws Exception {
		if (id!=null) {
			ReportGroup group = (ReportGroup)sessionManager.execute("from com.amkai.aes.generatedbeans.diee.ReportGroup x where x.id="+id).uniqueResult();
			if (group==null)
				throw new Exception("Report group #"+id+" not found in the database.");
			return group;
		}
		return null;
	}
	
	private final ReportDefinition getReportDefinition(Long id, SessionManager sessionManager) throws Exception {
		if (id!=null) {
			ReportDefinition def = (ReportDefinition)sessionManager.execute("from com.amkai.aes.generatedbeans.diee.ReportDefinition x where x.id="+id).uniqueResult();
			if (def==null)
				throw new Exception("Report definition #"+id+" not found in the database.");
			return def;
		}
		return null;
	}
	
	private final TaskXML getTaskXML(Long id, SessionManager sessionManager) throws Exception {
		if (id!=null) {
			TaskXML xml = (TaskXML)sessionManager.execute("from "+TaskXML.class.getCanonicalName()+" x where x.id="+id).uniqueResult();
			if (xml==null)
				throw new Exception("Task xml #"+id+" not found in the database.");
			return xml;
		}
		return null;
	}
	
	private final ReportTask getReportTask(Long id, SessionManager sessionManager) throws Exception {
		if (id!=null) {
			ReportTask task = (ReportTask)sessionManager.execute("from "+ReportTask.class.getCanonicalName()+" x where x.id="+id).uniqueResult();
			if (task==null)
				throw new Exception("Report task #"+id+" not found in the database.");
			return task;
		}
		return null;
	}
	
	private final ServerTask getServerTask(Long id, SessionManager sessionManager) throws Exception {
		if (id!=null) {
			ServerTask task = (ServerTask)sessionManager.execute("from "+ServerTask.class.getCanonicalName()+" x where x.id="+id).uniqueResult();
			if (task==null)
				throw new Exception("Server task #"+id+" not found in the database.");
			return task;
		}
		return null;
	}
	
	private final void walkTroughReportGroup(ReportGroup group) {
		group.initDirectFields();
		Set<ReportGroup> children = group.getChildren();
		if (children!=null) {
			for (ReportGroup g : children) walkTroughReportGroup(g);
		}
		Set<ReportDefinition> defs = group.getReportDefinitions();
		if (defs!=null) {
			for (ReportDefinition def : defs) {
				DIEEServerUtils.initReportDefinition(def);
			}
		}
		Set<TaskXML> xmls = group.getTaskXMLs();
		if (xmls!=null) {
			for (TaskXML xml : xmls) {
				DIEEServerUtils.initTaskXML(xml);
			}
		}
		Set<ReportTask> tasks = group.getReportTasks();
		if (tasks!=null) {
			for (ReportTask task : tasks) {
				DIEEServerUtils.initReportTask(task);
			}
		}
	}
	
	private final void deleteReportGroup(ReportGroup group, SessionManager sessionManager) {
		Set<ReportGroup> children = group.getChildren();
		if (children!=null)
			for (ReportGroup child : children) {
				deleteReportGroup(child, sessionManager);
			}
		Set<ReportDefinition> defs = group.getReportDefinitions();
		if (defs!=null) {
			for (ReportDefinition def : defs) {
				sessionManager.delete(def);
			}
		}
		Set<TaskXML> xmls = group.getTaskXMLs();
		if (xmls!=null) {
			for (TaskXML xml : xmls) {
				sessionManager.delete(xml);
			}
		}
		Set<ReportTask> tasks = group.getReportTasks();
		if (tasks!=null) {
			for (ReportTask task : tasks) {
				sessionManager.delete(task);
			}
		}
		sessionManager.delete(group);
	}
	
	private final void setFormPrintingKind(ReportGroup group, SessionManager sessionManager) {
		sessionManager.update(group);
		for (ReportGroup g : group.getChildren()) {
			g.setFormPrintingKind(group.getFormPrintingKind());
			setFormPrintingKind(g, sessionManager);
		}
	}
	
	private final void addActiveReportDefinitionsToList(ReportGroup group, DIEEResult result) {
		if (group.isActive()) {
			Set<ReportDefinition> defs = group.getReportDefinitions();
			if (defs!=null) {
				for (ReportDefinition def : defs) {
					result.addReportItem(DIEEServerUtils.initReportDefinition(def));
				}
			}
			for (ReportGroup g : group.getChildren()) {
				addActiveReportDefinitionsToList(g, result);
			}
		}
	}
	
	private final void deleteItems(int scope, List<Long> ids, DIEEResult result, SessionManager sessionManager) throws Exception {
		String s = getIdList(ids);
		String text = null;
		String table = null;
		sessionManager.openTransaction();
		switch (scope) {
		case DIEEJob.ReportClass.OPERATION_DELETE_DEFINITION:
			text = "report definition";
			table = ReportDefinition.class.getCanonicalName();
			break;
		case DIEEJob.ReportClass.OPERATION_DELETE_TASK_XML:
			text = "task xml";
			table = TaskXML.class.getCanonicalName();
			info("Check deleteable task xmls: "+s+" ...");
			Long cnt = (Long)sessionManager.execute("select count(*) from "+ServerTask.class.getCanonicalName()+" as t left join t.taskXML as x where x.id in ("+s+")").uniqueResult();
			if (cnt==0) {
				cnt = (Long)sessionManager.execute("select count(*) from "+ReportTask.class.getCanonicalName()+" as t left join t.taskXML as x where x.id in ("+s+")").uniqueResult();
			}
			if (cnt>0) {
				table = null;
				info("References found. Count: "+cnt+".");
				result.addErrorMessages("Delete not possible: there are references to the selected items.");
			}
			break;
		}
		if (s.length()>0 && table!=null) {
			info("Deleting the "+text+" with id: "+s+" ...");
			sessionManager.execute("delete from "+table+" x where x.id in ("+s+")").executeUpdate();
			sessionManager.commitTransaction();
		} else {
			sessionManager.rollbackTransaction();
		}
	}
	
	private final void writeDataToFile(Object data, String fileName) throws IOException {
		File file = GeneratedFiles.getGeneratedFile(fileName);
		if (!file.exists()) file.createNewFile();
		if (data==null) {
			Utils.saveStringToFile("Data is null", file);
			GeneratedFiles.saveObject(fileName, "Data is null");
		} else if (data instanceof String) {
			Utils.saveStringToFile((String)data, file);
		} else if (data instanceof byte[]) {
			DIEECommonUtils.writeStreamToStream(new ByteArrayInputStream((byte[])data), new FileOutputStream(file), true);
		} else if (data instanceof Document) {
			FileWriter writer = new FileWriter(file);
			XMLSerializer serializer = new XMLSerializer(writer, new OutputFormat(Method.XML, null, true));
			serializer.serialize((Document)data);
			writer.flush();
			writer.close();
		} else if (data instanceof Serializable) {
			GeneratedFiles.saveObject(fileName, (Serializable)data);
		} else {
			Utils.saveStringToFile("Data is not serializable: "+data.getClass().getCanonicalName(), file);
		}
	}
	
}
